package lib.quasar.widget.edit;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.support.annotation.IntRange;
import android.text.InputFilter;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;
import android.widget.EditText;

import java.util.regex.Pattern;

import lib.quasar.util.LogUtil;
import lib.quasar.widget.R;

/**
 * description: 当前类描述信息
 * created by kalu on 2018/4/24 21:11
 */
@SuppressLint("AppCompatCustomView")
public class AlterEditText extends EditText {

//    private final String PLACEHOLDER = "☯";

//    // 汉字正则
//    private final String PATTERN_HANZI = "[\\u4e00-\\u9fa5]";
//    // 小数(带1-2位小数的正数或负数：^(\-)?\d+(\.\d{1,2})?$)
//    private final String PATTERN_FLOAT = "^(\\-)?\\d+(\\.\\d{1," + PLACEHOLDER + "})?$";
//    // 整数
//    private final String PATTERN_INT = "^(0|[1-9][0-9]*|-[1-9][0-9]*)$";

    private final int MODEL_NULL = 1;
    private final int MODEL_HANZI = 2;
    private int MODEL_NUMBER = 3;

    private int modelType = 1;
    private String matcherFilter;

    private int hanziLength = -1;

    private boolean textBold = false;

    private final int[][] mState = new int[][]{
            new int[]{android.R.attr.state_pressed},
            new int[]{android.R.attr.state_enabled}
    };

    private final StateListDrawable mBackgroundDrawable = new StateListDrawable();
    private final GradientDrawable mNormalDrawable = new GradientDrawable();
    private final GradientDrawable mPressDrawable = new GradientDrawable();

    private int backgroundColorNormal = Color.TRANSPARENT;
    private int backgroundColorPress = Color.TRANSPARENT;

    private float iconWidthLeft = 0f;
    private float iconHeightLeft = 0f;

    private float iconWidthRight = 0f;
    private float iconHeightRight = 0f;

    private float lineSize = 0f;
    private int lineColor = Color.TRANSPARENT;

    private float minWarning = -1f, maxWarning = -1f;
    private float maxInput = -1f, minInput = -1f;

    private int minWarningColor = Color.BLUE;
    private int maxWarningColor = Color.RED;
    private int normalTextColor = Color.BLACK;

    private boolean localtionTop = false;
    private boolean localtionBottom = false;
    private boolean localtionLeft = false;
    private boolean localtionRight = false;

    private float paddingTop = 0;
    private float paddingBottom = 0;
    private float paddingLeft = 0;
    private float paddingRight = 0;

    private CharSequence modelText;

    public AlterEditText(Context context) {
        super(context);
    }

    public AlterEditText(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray array = null;
        try {
            array = context.obtainStyledAttributes(attrs, R.styleable.AlterEditText);

            localtionTop = array.getBoolean(R.styleable.AlterEditText_aet_location_top, false);
            localtionBottom = array.getBoolean(R.styleable.AlterEditText_aet_location_bottom, false);
            localtionLeft = array.getBoolean(R.styleable.AlterEditText_aet_location_left, false);
            localtionRight = array.getBoolean(R.styleable.AlterEditText_aet_location_right, false);

            paddingTop = array.getDimension(R.styleable.AlterEditText_aet_padding_top, 0);
            paddingBottom = array.getDimension(R.styleable.AlterEditText_aet_padding_bottom, 0);
            paddingLeft = array.getDimension(R.styleable.AlterEditText_aet_padding_left, 0);
            paddingRight = array.getDimension(R.styleable.AlterEditText_aet_padding_right, 0);

            iconWidthLeft = array.getDimension(R.styleable.AlterEditText_aet_icon_width_left, iconWidthLeft);
            iconHeightLeft = array.getDimension(R.styleable.AlterEditText_aet_icon_height_left, iconHeightLeft);

            iconWidthRight = array.getDimension(R.styleable.AlterEditText_aet_icon_width_right, iconWidthRight);
            iconHeightRight = array.getDimension(R.styleable.AlterEditText_aet_icon_height_right, iconHeightRight);

            maxInput = array.getFloat(R.styleable.AlterEditText_aet_input_max, maxInput);
            minInput = array.getFloat(R.styleable.AlterEditText_aet_input_min, minInput);
            maxWarning = array.getFloat(R.styleable.AlterEditText_aet_warning_max, maxWarning);
            minWarning = array.getFloat(R.styleable.AlterEditText_aet_warning_min, minWarning);

            minWarningColor = array.getColor(R.styleable.AlterEditText_aet_text_color_warning_min, minWarningColor);
            maxWarningColor = array.getColor(R.styleable.AlterEditText_aet_text_color_warning_max, maxWarningColor);
            normalTextColor = array.getColor(R.styleable.AlterEditText_aet_text_color_normal, normalTextColor);
            textBold = array.getBoolean(R.styleable.AlterEditText_aet_text_bold, textBold);

            final float radius = array.getDimension(R.styleable.AlterEditText_aet_bg_radius, 0);
            final float stock = array.getDimension(R.styleable.AlterEditText_aet_stock_size, 0);

            backgroundColorNormal = array.getColor(R.styleable.AlterEditText_aet_bg_color_normal, Color.TRANSPARENT);
            final int color2 = array.getColor(R.styleable.AlterEditText_aet_stock_color_normal, Color.TRANSPARENT);
            mNormalDrawable.setColor(backgroundColorNormal);
            mNormalDrawable.setCornerRadius(radius);
            mNormalDrawable.setStroke((int) stock, color2);

            backgroundColorPress = array.getColor(R.styleable.AlterEditText_aet_bg_color_press, Color.TRANSPARENT);
            final int color4 = array.getColor(R.styleable.AlterEditText_aet_stock_color_press, Color.TRANSPARENT);
            mPressDrawable.setColor(backgroundColorPress);
            mPressDrawable.setCornerRadius(radius);
            mPressDrawable.setStroke((int) stock, color4);

            lineSize = array.getDimension(R.styleable.AlterEditText_aet_line_size, lineSize);
            lineColor = array.getColor(R.styleable.AlterEditText_aet_line_color, lineColor);
        } catch (Exception e) {
            LogUtil.e("", e.getMessage(), e);
        } finally {
            if (null == array) return;
            array.recycle();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // 左,上,右,下
        final Drawable[] drawables = getCompoundDrawables();
        if (null != drawables[0] && iconWidthLeft != 0 && iconHeightLeft != 0f) {
            final Drawable drawable = drawables[0];
            final Rect bounds = drawable.getBounds();
            if (bounds.width() != 0 && bounds.height() != 0) {
                final int newLeft = bounds.left;
                final int newTop = (int) (bounds.height() * 0.5f - iconHeightLeft * 0.5f);
                final int newBottom = (int) (bounds.height() * 0.5f + iconHeightLeft * 0.5f);
                final int newRight = (int) (newLeft + iconWidthLeft);
                drawable.setBounds(newLeft, newTop, newRight, newBottom);
            }
        }
        if (null != drawables[2] && iconWidthRight != 0 && iconHeightRight != 0f) {
            final Drawable drawable = drawables[2];
            final Rect bounds = drawable.getBounds();
            if (bounds.width() != 0 && bounds.height() != 0) {
                final int newLeft = bounds.left;
                final int newTop = (int) (bounds.height() * 0.5f - iconHeightRight * 0.5f);
                final int newBottom = (int) (bounds.height() * 0.5f + iconHeightRight * 0.5f);
                final int newRight = (int) (newLeft + iconWidthRight);
                drawable.setBounds(newLeft, newTop, newRight, newBottom);
            }
        }
        setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);

        int height = getHeight();
        int width = getWidth();
        getPaint().setColor(lineColor);
        getPaint().setAntiAlias(true);
        getPaint().setFilterBitmap(true);
        getPaint().setDither(true);
        getPaint().setStrokeCap(Paint.Cap.ROUND);
        getPaint().setStrokeJoin(Paint.Join.ROUND);
        getPaint().setStyle(Paint.Style.FILL);

        if (localtionTop) {
            canvas.drawRect(paddingLeft, 0, width - paddingRight, lineSize, getPaint());
        }

        if (localtionBottom) {
            canvas.drawRect(paddingLeft, height - lineSize, width - paddingRight, height, getPaint());
        }

        if (localtionLeft) {
            canvas.drawRect(paddingLeft, paddingTop, lineSize, height - paddingBottom, getPaint());
        }

        if (localtionRight) {
            canvas.drawRect(width - paddingRight - lineSize, paddingTop, width - paddingRight, height - paddingBottom, getPaint());
        }
    }

    @Override
    public void draw(Canvas canvas) {

        if (backgroundColorNormal != Color.TRANSPARENT && backgroundColorPress != Color.TRANSPARENT) {
            mBackgroundDrawable.addState(mState[0], mPressDrawable);
            mBackgroundDrawable.addState(mState[1], mNormalDrawable);
//        mBackgroundDrawable.setEnterFadeDuration(50);
//        mBackgroundDrawable.setExitFadeDuration(50);
            setBackgroundDrawable(mBackgroundDrawable);
        }

        getPaint().setFakeBoldText(textBold);
        super.draw(canvas);

        int height = getHeight();
        int width = getWidth();
        getPaint().setColor(lineColor);
        getPaint().setAntiAlias(true);
        getPaint().setFilterBitmap(true);
        getPaint().setDither(true);
        getPaint().setStrokeCap(Paint.Cap.ROUND);
        getPaint().setStrokeJoin(Paint.Join.ROUND);
        getPaint().setStyle(Paint.Style.FILL);

        if (localtionTop) {
            canvas.drawRect(paddingLeft, 0, width - paddingRight, lineSize, getPaint());
        }

        if (localtionBottom) {
            canvas.drawRect(paddingLeft, height - lineSize, width - paddingRight, height, getPaint());
        }

        if (localtionLeft) {
            canvas.drawRect(paddingLeft, paddingTop, lineSize, height - paddingBottom, getPaint());
        }

        if (localtionRight) {
            canvas.drawRect(width - paddingRight - lineSize, paddingTop, width - paddingRight, height - paddingBottom, getPaint());
        }
    }

//    @Override
//    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
//
//        if (null != listener && direction == 0 && !focused) {
//            final String s = getText().toString();
//            if (!TextUtils.isEmpty(s)) {
//                listener.onInputChange(s.trim(), false, true);
//            }
//        }
//
//        super.onFocusChanged(focused, direction, previouslyFocusedRect);
//    }


    @Override
    public void setText(CharSequence text, BufferType type) {
       // LogUtil.e("hjhj", "setText ==> " + text);

//        if (null != listener && !TextUtils.isEmpty(text)) {
//            listener.onInputChange(text.toString(), false);
//        }

        super.setText(text, type);
    }

    /*********************************************************************************************/

    public final void setNormalBackgroundColor(int color) {
        mNormalDrawable.setColor(color);
    }

    public final void setPressBackgroundColor(int color) {
        mPressDrawable.setColor(color);
    }

    public final void setRadius(int radius) {
        mNormalDrawable.setCornerRadius(radius);
        mPressDrawable.setCornerRadius(radius);
    }

    public float getMinInput() {
        return minInput;
    }

    public float getMaxInput() {
        return maxInput;
    }

    public void setMaxInput(float maxInput) {
        this.maxInput = maxInput;
    }

    public void setMinInput(float minInput) {
        this.minInput = minInput;
    }

    public float getMinWarning() {
        return minWarning;
    }

    public float getMaxWarning() {
        return maxWarning;
    }

    public void setMaxWarning(float maxWarning) {
        this.maxWarning = maxWarning;
    }

    public void setMinWarning(float minWarning) {
        this.minWarning = minWarning;
    }

    public void setMaxLength(int length) {
        super.setFilters(new InputFilter[]{new InputFilter.LengthFilter(length)}); //最大输入长度
    }

    public void setModelText(CharSequence str) {

        if (!TextUtils.isEmpty(modelText)) return;
        modelText = str;
    }

    public void setInputType(int type) {
        super.setInputType(type); //输入类型
    }

    /**
     * @param inputLength 总长度
     */
    public void setHanziFilter(@IntRange(from = 1, to = Integer.MAX_VALUE) int inputLength) {
        this.modelType = MODEL_HANZI;
        this.hanziLength = inputLength;
        matcherFilter = "[\u4e00-\u9fa5]{1," + inputLength + "}$";
    }

    /**
     * @param dotLength   小数点长度
     * @param inputLength 总长度
     */
    public void setNumberFilter(@IntRange(from = 1, to = Integer.MAX_VALUE) int dotLength,
                                @IntRange(from = 1, to = Integer.MAX_VALUE) int inputLength) {
        this.modelType = MODEL_NUMBER;
        // 长度最多10位，允许3位小数
        // patternStr = "^(?=([0-9]{1,10}$|[0-9]{1,7}\\.))(0|[1-9][0-9]*)(\\.[0-9]{1,3})?$";
        matcherFilter = "^(?=([0-9]{1," + inputLength + "}$|[0-9]{1," + (inputLength - dotLength) + "}\\.))(0|[1-9][0-9]*)(\\.[0-9]{1," + dotLength + "})?$";
    }

    /*****************************************************************************************/

    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        return new AlterEditText.InputWrapper(super.onCreateInputConnection(outAttrs), false);
    }

    private final class InputWrapper extends InputConnectionWrapper implements InputConnection {

        public InputWrapper(InputConnection target, boolean mutable) {
            super(target, mutable);
        }

        @Override
        public boolean commitText(CharSequence text, int newCursorPosition) {
           // LogUtil.e("hjhj", "commitText");

            final String before = getText().toString().trim();
            // LogUtil.e("commitText", "before = " + before + ", text = " + text + ", position = " + getSelectionStart());
            final String after = new StringBuilder(before).insert(getSelectionStart(), text).toString();

            // 汉字
            if (modelType == MODEL_HANZI) {

                if (hanziLength != -1 && text.length() > hanziLength) {
                    text = text.subSequence(0, hanziLength);
                }

                if (hanziLength != -1 && !TextUtils.isEmpty(before) && before.length() == hanziLength)
                    return false;

                final boolean ok = Pattern.compile(matcherFilter).matcher(text).matches();
                if (!ok) return false;

                if (hanziLength != -1 && after.length() > hanziLength) {
                    final int length = before.length();
                    final int end = hanziLength - length;
                    text = text.subSequence(0, end);
                }

                if (null != listener) {
                    boolean isModelChange = (null != modelText && !modelText.equals(after));
                    listener.onInputChange(after, isModelChange, false);
                }
            }
            // 小数
            else if (modelType == MODEL_NUMBER) {

                if (".".equals(text)) {

                    // 输入之前没有内容
                    if (TextUtils.isEmpty(before)) {
                        return false;
                    }
                    // 输入之前存在内容
                    else {
                        final int begin = before.indexOf(String.valueOf(text));
                        final int end = before.lastIndexOf(String.valueOf(text));

                        // 没有小数点
                        if (begin == -1 && end == -1) {

                        }
                        // 有一个小数点
                        else if (begin == end) {
                            return false;
                        }
                        // 有多个小数点
                        else {
                            return false;
                        }
                    }
                } else {
                    final boolean ok = Pattern.compile(matcherFilter).matcher(after).matches();
                    if (!ok) return false;
                }

                // 警告最小值,最大值, 边界最小值,最大值
                try {

                    final float afterFloat = Float.parseFloat(after);
                    // LogUtil.e("commitText", "before = " + before + ", after = " + after + ", afterFloat = " + afterFloat + ", maxInput = " + maxInput + ", minInput = " + minInput);

                    if (maxInput != -1 && afterFloat > maxInput) {
                        if (null != listener) {
                            listener.onInputChange(after, false, true);
                        }
                        return false;
                    }

                    if (minInput != -1 && afterFloat < minInput) {
                        getText().clear();
                        text = String.valueOf(minInput);
                    }

                    // 小于警告最小值
                    if (minWarning != -1 && afterFloat < minWarning) {
                        setTextColor(minWarningColor);
                    }
                    // 大于警告最大值
                    else if (maxWarning != -1 && afterFloat > maxWarning) {
                        setTextColor(maxWarningColor);
                    }
                    // 正常
                    else {
                        setTextColor(normalTextColor);
                    }

                } catch (Exception e) {
                    setTextColor(normalTextColor);
                    LogUtil.e("", e.getMessage(), e);
                }

                if (null != listener) {
                    boolean isModelChange = (null != modelText && !modelText.equals(after));
                    listener.onInputChange(after, isModelChange, false);
                }
            }

            final boolean ok = super.commitText(text, newCursorPosition);
            return ok;
        }

        @Override
        public boolean sendKeyEvent(KeyEvent event) {

            if (null == listener || event.getAction() != KeyEvent.ACTION_DOWN || event.getKeyCode() != KeyEvent.KEYCODE_DEL)
                return super.sendKeyEvent(event);

            final int selectionStart = getSelectionStart();
            if (selectionStart == 0)
                return super.sendKeyEvent(event);


            final String before = getText().toString();
            if (TextUtils.isEmpty(before) || TextUtils.isEmpty(before.trim()))
                return super.sendKeyEvent(event);

            final String after = new StringBuilder(before).delete(selectionStart - 1, selectionStart).toString();
            boolean isModelChange = (null != modelText && !modelText.equals(after));
            listener.onInputChange(after, isModelChange, false);

            try {
                final float afterFloat = Float.parseFloat(after);
                // 小于警告最小值
                if (minWarning != -1 && afterFloat < minWarning) {
                    setTextColor(minWarningColor);
                }
                // 大于警告最大值
                else if (maxWarning != -1 && afterFloat > maxWarning) {
                    setTextColor(maxWarningColor);
                }
                // 正常
                else {
                    setTextColor(normalTextColor);
                }
            } catch (Exception e) {
                setTextColor(normalTextColor);
            }
            return super.sendKeyEvent(event);
        }
    }

    /*********************************************************************************************/

    private OnInputChangeListener listener;

    public interface OnInputChangeListener {
        void onInputChange(String input, boolean isModelChange, boolean isMax);
    }

    public void setOnInputChangeListener(OnInputChangeListener listener) {
        this.listener = listener;
    }
}
